﻿using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using Xtro.DirectX.Direct3D;
using Xtro.Gerecler;
using Xtro.MDX.Direct3D10;

namespace XtroDirectXDemo
{
    // ReSharper disable InconsistentNaming
    internal sealed partial class FormSetup : Form
    // ReSharper restore InconsistentNaming
    {
        public struct SSettings
        {
            public uint AntialiasingNo;
            public bool Fullscreen;
            public uint MonitorNo;
            public bool AllDisplayModes;
            public uint DisplayModeNo;
            public uint RefreshRateNo;
        }

        internal static SSettings Panel1Settings;
        internal static SSettings Panel2Settings;
        internal static SSettings WindowSettings;

        sealed class TResolutionItem
        {
            readonly string Text;

            public readonly uint DisplayModeNo;

            public TResolutionItem(string Text, uint DisplayModeNo)
            {
                this.Text = Text;
                this.DisplayModeNo = DisplayModeNo;
            }

            public override string ToString()
            {
                return Text;
            }
        }

        void FillAntialiasings()
        {
            ComboBoxAntialiasing.Items.Clear();

            foreach (var SampleDescription in Manager.Adapters[ComboBoxAdapter.SelectedIndex].Samplings)
            {
                if (SampleDescription.Count == 1 && SampleDescription.Quality == 0) ComboBoxAntialiasing.Items.Add("Disabled");
                else ComboBoxAntialiasing.Items.Add("S" + SampleDescription.Count + ", Q" + SampleDescription.Quality);
            }

            ComboBoxAntialiasing.SelectedIndex = 0;
        }

        void FillMonitors()
        {
            ComboBoxMonitor.Items.Clear();

            foreach (var Monitor in Manager.Adapters[ComboBoxAdapter.SelectedIndex].Monitors)
            {
                var DisplayDevice = new Windows.SDisplayDevice { Cb = Marshal.SizeOf(typeof(Windows.SDisplayDevice)) };
                if (!Windows.EnumDisplayDevices(Monitor.Description.DeviceName, 0, ref DisplayDevice, 0)) throw new EGerecler(Name, GetType(), "Display device '" + Monitor.Description.DeviceName + "' could not be found.", Name);
                ComboBoxMonitor.Items.Add(DisplayDevice.DeviceString);
            }

            ComboBoxMonitor.SelectedIndex = 0;
        }

        void FillResolutions()
        {
            ListBoxResolution.Items.Clear();

            var Monitor = Manager.Adapters[ComboBoxAdapter.SelectedIndex].Monitors[ComboBoxMonitor.SelectedIndex];
            var MonitorAspectRatio = (float)(Monitor.Description.DesktopCoordinates.Width) / (Monitor.Description.DesktopCoordinates.Height);

            for (var A = 0; A < Monitor.DisplayModes.Count; A++)
            {
                var DisplayMode = Monitor.DisplayModes[A];

                if (CheckBoxAllAspectRatios.Checked || Math.Abs(MonitorAspectRatio - (float)DisplayMode.Width / DisplayMode.Height) < 0.01) ListBoxResolution.Items.Add(new TResolutionItem(DisplayMode.Width + " x " + DisplayMode.Height, (uint)A));
            }

            ListBoxResolution.SelectedIndex = 0;
        }

        void FillFrequencies()
        {
            ListBoxFrequency.Items.Clear();

            var SelectedItem = (TResolutionItem)ListBoxResolution.SelectedItem;
            if (SelectedItem == null) throw new EGerecler("ListBoxResolution.SelectedItem", typeof(TResolutionItem), ResourcesReason.Empty, Name);

            foreach (var RefreshRate in Manager.Adapters[ComboBoxAdapter.SelectedIndex].Monitors[ComboBoxMonitor.SelectedIndex].DisplayModes[(int)SelectedItem.DisplayModeNo].RefreshRates)
            {
                ListBoxFrequency.Items.Add(Manager.RationalToFloat(RefreshRate).ToString("0") + " Hz");
            }

            ListBoxFrequency.SelectedIndex = ListBoxFrequency.Items.Count - 1;
        }

        readonly FormMain FormMain;

        public FormSetup(FormMain FormMain)
        {
            this.FormMain = FormMain;

            InitializeComponent();
        }

        public void FillAdapters()
        {
            ComboBoxAdapter.Items.Clear();

            foreach (var Adapter in Manager.Adapters)
            {
                ComboBoxAdapter.Items.Add(Adapter.Description.Description);
            }
            ComboBoxAdapter.SelectedIndex = 0;
        }

        bool OldLooping;

        int CancelAdapterNo;
        bool CancelDebug;
        bool CancelVerticalSync;
        bool CancelRenderTarget1;
        bool CancelRenderTarget2;
        bool CancelRenderTarget3;
        SSettings CancelPanel1Settings;
        SSettings CancelPanel2Settings;
        SSettings CancelWindowSettings;

        void SaveForCancel()
        {
            CancelAdapterNo = ComboBoxAdapter.SelectedIndex;
            CancelDebug = CheckBoxDebugLayer.Checked;
            CancelVerticalSync = CheckBoxVerticalSync.Checked;
            CancelRenderTarget1 = CheckBoxRenderTarget1.Checked;
            CancelRenderTarget2 = CheckBoxRenderTarget2.Checked;
            CancelRenderTarget3 = CheckBoxRenderTarget3.Checked;
            CancelPanel1Settings = Panel1Settings;
            CancelPanel2Settings = Panel2Settings;
            CancelWindowSettings = WindowSettings;
        }

        void LoadForCancel()
        {
            ComboBoxAdapter.SelectedIndex = CancelAdapterNo;
            CheckBoxDebugLayer.Checked = CancelDebug;
            CheckBoxVerticalSync.Checked = CancelVerticalSync;
            CheckBoxRenderTarget1.Checked = CancelRenderTarget1;
            CheckBoxRenderTarget2.Checked = CancelRenderTarget2;
            CheckBoxRenderTarget3.Checked = CancelRenderTarget3;
            Panel1Settings = CancelPanel1Settings;
            Panel2Settings = CancelPanel2Settings;
            WindowSettings = CancelWindowSettings;
        }

        private void FormSetup_Shown(object Sender, EventArgs E)
        {
            OldLooping = FormMain.CheckBoxLooping.Checked;
            FormMain.CheckBoxLooping.Checked = false;

            LoadFromContext();

            SaveForCancel();
        }

        private void LoadFromContext()
        {
            ComboBoxAdapter.SelectedIndex = FormMain.Context.AdapterNo;
            CheckBoxDebugLayer.Checked = (FormMain.Context.Flags & CreateDeviceFlag.Debug) > 0;

            if (FormMain.ScreenPanel1 != null) CheckBoxVerticalSync.Checked = FormMain.ScreenPanel1.VerticalSync;
            else if (FormMain.ScreenPanel2 != null) CheckBoxVerticalSync.Checked = FormMain.ScreenPanel2.VerticalSync;
            else if (FormMain.ScreenWindow != null) CheckBoxVerticalSync.Checked = FormMain.ScreenWindow.VerticalSync;

            CheckBoxRenderTarget1.Checked = FormMain.ScreenPanel1 != null;
            CheckBoxRenderTarget2.Checked = FormMain.ScreenPanel2 != null;
            CheckBoxRenderTarget3.Checked = FormMain.ScreenWindow != null;

            RadioButtonRenderTarget_CheckedChanged(null, null);
        }

        private void FormSetup_FormClosing(object Sender, FormClosingEventArgs E)
        {
            if (DialogResult == DialogResult.Cancel)
            {
                LoadForCancel();

                RadioButtonRenderTarget_CheckedChanged(null, null);
            }

            FormMain.CheckBoxLooping.Checked = OldLooping;
        }

        private void ComboBoxAdapter_SelectedIndexChanged(object Sender, EventArgs E)
        {
            FillMonitors();
            FillAntialiasings();
        }

        private void ComboBoxMonitor_SelectedIndexChanged(object Sender, EventArgs E)
        {
            FillResolutions();

            if (LoadingSettings) return;

            if (RadioButtonRenderTarget1.Checked) Panel1Settings.MonitorNo = (uint)ComboBoxMonitor.SelectedIndex;
            else if (RadioButtonRenderTarget2.Checked) Panel2Settings.MonitorNo = (uint)ComboBoxMonitor.SelectedIndex;
            else WindowSettings.MonitorNo = (uint)ComboBoxMonitor.SelectedIndex;
        }

        private void CheckBoxAllAspectRatios_CheckedChanged(object Sender, EventArgs E)
        {
            FillResolutions();

            if (LoadingSettings) return;

            if (RadioButtonRenderTarget1.Checked) Panel1Settings.AllDisplayModes = CheckBoxAllAspectRatios.Checked;
            else if (RadioButtonRenderTarget2.Checked) Panel2Settings.AllDisplayModes = CheckBoxAllAspectRatios.Checked;
            else WindowSettings.AllDisplayModes = CheckBoxAllAspectRatios.Checked;
        }

        private void ListBoxResolution_SelectedIndexChanged(object Sender, EventArgs E)
        {
            FillFrequencies();

            if (LoadingSettings) return;

            var SelectedItem = (TResolutionItem)ListBoxResolution.SelectedItem;
            if (SelectedItem == null) throw new EGerecler("ListBoxResolution.SelectedItem", typeof(TResolutionItem), ResourcesReason.Empty, Name);

            if (RadioButtonRenderTarget1.Checked) Panel1Settings.DisplayModeNo = SelectedItem.DisplayModeNo;
            else if (RadioButtonRenderTarget2.Checked) Panel2Settings.DisplayModeNo = SelectedItem.DisplayModeNo;
            else WindowSettings.DisplayModeNo = SelectedItem.DisplayModeNo;
        }

        private void ListBoxFrequency_SelectedIndexChanged(object Sender, EventArgs E)
        {
            if (LoadingSettings) return;

            if (RadioButtonRenderTarget1.Checked) Panel1Settings.RefreshRateNo = (uint)ListBoxFrequency.SelectedIndex;
            else if (RadioButtonRenderTarget2.Checked) Panel2Settings.RefreshRateNo = (uint)ListBoxFrequency.SelectedIndex;
            else WindowSettings.RefreshRateNo = (uint)ListBoxFrequency.SelectedIndex;
        }

        private void CheckBoxFullscreen_CheckedChanged(object Sender, EventArgs E)
        {
            GroupBoxResolution.Enabled = CheckBoxFullscreen.Checked;
            ListBoxResolution_SelectedIndexChanged(null, null);

            if (LoadingSettings) return;

            if (RadioButtonRenderTarget1.Checked) Panel1Settings.Fullscreen = CheckBoxFullscreen.Checked;
            else if (RadioButtonRenderTarget2.Checked) Panel2Settings.Fullscreen = CheckBoxFullscreen.Checked;
            else WindowSettings.Fullscreen = CheckBoxFullscreen.Checked;
        }

        private void CheckBoxRenderTarget_CheckedChanged(object Sender, EventArgs E)
        {
            if (Sender is CheckBox && ((CheckBox)Sender).Checked)
            {
                if (Sender == CheckBoxRenderTarget1) RadioButtonRenderTarget1.Checked = true;
                else if (Sender == CheckBoxRenderTarget2) RadioButtonRenderTarget2.Checked = true;
                else if (Sender == CheckBoxRenderTarget3) RadioButtonRenderTarget3.Checked = true;
            }
        }

        bool LoadingSettings;
        private void RadioButtonRenderTarget_CheckedChanged(object Sender, EventArgs E)
        {
            if (Sender is RadioButton && !((RadioButton)Sender).Checked) return; // We let only checked=true event

            LoadingSettings = true;

            SSettings Settings;

            CheckBoxFullscreen.Checked = false;
            CheckBoxFullscreen.Enabled = false;
            CheckBoxFullscreen_CheckedChanged(null, null);

            if (RadioButtonRenderTarget1.Checked) Settings = Panel1Settings;
            else if (RadioButtonRenderTarget2.Checked) Settings = Panel2Settings;
            else // Window
            {
                Settings = WindowSettings;

                CheckBoxFullscreen.Checked = Settings.Fullscreen;
                CheckBoxFullscreen.Enabled = true;
            }

            ComboBoxAntialiasing.SelectedIndex = (int)Settings.AntialiasingNo;
            CheckBoxAllAspectRatios.Checked = Settings.AllDisplayModes;

            var Index = 0;
            for (var A = 0; A < ListBoxResolution.Items.Count; A++)
            {
                if (((TResolutionItem)(ListBoxResolution.Items[A])).DisplayModeNo == Settings.DisplayModeNo)
                {
                    Index = A;
                    break;
                }
            }
            ListBoxResolution.SelectedIndex = Index;

            ListBoxFrequency.SelectedIndex = (int)Settings.RefreshRateNo;

            LoadingSettings = false;
        }

        private void ComboBoxAntialiasing_SelectedIndexChanged(object Sender, EventArgs E)
        {
            if (LoadingSettings) return;

            if (RadioButtonRenderTarget1.Checked) Panel1Settings.AntialiasingNo = (uint)ComboBoxAntialiasing.SelectedIndex;
            else if (RadioButtonRenderTarget2.Checked) Panel2Settings.AntialiasingNo = (uint)ComboBoxAntialiasing.SelectedIndex;
            else WindowSettings.AntialiasingNo = (uint)ComboBoxAntialiasing.SelectedIndex;
        }
    }
}